package com.kexio.user.controller;

import java.util.List;
import java.util.Collections;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.util.StringUtils;

import com.kexio.auth.annotation.RequiresPermission;
import com.kexio.auth.annotation.RateLimit;
import com.kexio.auth.util.AuthContextUtils;
import com.kexio.common.dto.PageResponse;
import com.kexio.common.page.PageQuery;
import com.kexio.common.page.PageUtils;
import com.kexio.common.page.PageConverters;
import com.kexio.common.dto.Result;
import com.kexio.common.exception.BusinessException;
import com.kexio.user.dto.MenuDTO;
import com.kexio.user.dto.MenuStatistics;
import com.kexio.user.entity.Menu;
import com.kexio.user.entity.Permission;
import com.kexio.user.service.MenuService;
import com.kexio.user.service.UserService;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;

/**
 * 菜单管理控制器
 * 
 * 提供菜单管理的REST API接口，包括：
 * - 菜单CRUD操作
 * - 菜单树形结构查询
 * - 菜单权限关联
 * - 用户菜单过滤
 * - 菜单导航构建
 * - 菜单统计信息
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@RestController
@RequestMapping("/menus")
@Tag(name = "菜单管理", description = "菜单管理相关API")
public class MenuController {
    
    private static final Logger logger = LoggerFactory.getLogger(MenuController.class);
    
    private final MenuService menuService;
    private final UserService userService;
    
    public MenuController(MenuService menuService, UserService userService) {
        this.menuService = menuService;
        this.userService = userService;
    }
    
    // ==================== 基础CRUD操作 ====================
    
    /**
     * 创建菜单
     */
    @PostMapping
    @RequiresPermission("menu:create")
    @RateLimit(count = 20, time = 1)
    @Operation(summary = "创建菜单", description = "创建新的菜单")
    public Result<MenuDTO> createMenu(
            @Valid @RequestBody MenuDTO request) {
        
        logger.info("创建菜单请求: name={}, tenantId={}", 
            request.getName(), AuthContextUtils.getCurrentTenantId());
        
        request.clearIdsForCreate();
        request.validate();
        
        // 将DTO转换为Menu实体
        Menu menu = request.toEntity();
        if (menu == null) {
            throw BusinessException.of("菜单信息转换失败");
        }
        menu = menuService.createMenu(menu);
        MenuDTO menuDTO = MenuDTO.fromEntity(menu);
        
        logger.info("创建菜单成功: menuId={}, menuName={}", 
            menu.getId(), menu.getName());
        
        return Result.success("菜单创建成功", menuDTO);
    }
    
    /**
     * 更新菜单
     */
    @PutMapping("/{menuId}")
    @RequiresPermission("menu:update")
    @RateLimit(count = 30, time = 1)
    @Operation(summary = "更新菜单信息", description = "更新指定菜单的信息")
    public Result<MenuDTO> updateMenu(
            @Parameter(description = "菜单ID") @PathVariable String menuId,
            @Valid @RequestBody MenuDTO request) {
        
        logger.info("更新菜单请求: menuId={}, tenantId={}", 
            menuId, AuthContextUtils.getCurrentTenantId());
        
        // 验证并清理请求数据
        request.validate();
        
        if (!request.hasAnyUpdateFields()) {
            logger.warn("更新菜单请求无任何更新内容: menuId={}", menuId);
            return Result.error("请提供要更新的内容");
        }
        
        // 将DTO转换为Menu实体
        Menu menu = request.toEntity();
        if (menu == null) {
            throw BusinessException.of("菜单更新信息转换失败");
        }
        menu = menuService.updateMenu(menuId, menu);
        MenuDTO menuDTO = MenuDTO.fromEntity(menu);
        
        logger.info("更新菜单成功: menuId={}, menuName={}", 
            menu.getId(), menu.getName());
        
        return Result.success("菜单更新成功", menuDTO);
    }
    
    /**
     * 删除菜单
     */
    @DeleteMapping("/{menuId}")
    @RequiresPermission("menu:delete")
    @RateLimit(count = 10, time = 1)
    @Operation(summary = "删除菜单", description = "删除指定的菜单（逻辑删除）")
    public Result<Void> deleteMenu(
            @Parameter(description = "菜单ID") @PathVariable String menuId) {
        
        logger.info("删除菜单请求: menuId={}", menuId);
        
        boolean success = menuService.deleteMenu(menuId);
        
        if (!success) {
            logger.warn("删除菜单失败: menuId={}", menuId);
            return Result.error("菜单不存在或已被删除");
        }
        
        logger.info("删除菜单成功: menuId={}", menuId);
        return Result.<Void>success("菜单删除成功", null);
    }
    
    /**
     * 获取菜单详情
     */
    @GetMapping("/{menuId}")
    @RequiresPermission("menu:query")
    @Operation(summary = "获取菜单详情", description = "获取指定菜单的详细信息")
    public Result<MenuDTO> getMenu(
            @Parameter(description = "菜单ID") @PathVariable String menuId) {
        
        logger.debug("获取菜单详情请求: menuId={}", menuId);
        
        Menu menu = menuService.getMenuById(menuId);
        
        if (menu == null) {
            logger.warn("菜单不存在: menuId={}", menuId);
            return Result.error("菜单不存在");
        }
        
        MenuDTO menuDTO = MenuDTO.fromEntity(menu);
        
        logger.debug("获取菜单详情成功: menuId={}, menuName={}", 
            menu.getId(), menu.getName());
        
        return Result.success("获取成功", menuDTO);
    }
    
    // ==================== 菜单列表查询 ====================
    
    /**
     * 分页查询菜单
     */
    @GetMapping
    @RequiresPermission("menu:query")
    @Operation(summary = "分页查询菜单", description = "根据条件分页查询菜单列表")
    public Result<PageResponse<MenuDTO>> queryMenus(
            @Parameter(description = "菜单类型") @RequestParam(required = false) String menuType,
            @Parameter(description = "菜单名称") @RequestParam(required = false) String menuName,
            @Parameter(description = "状态") @RequestParam(required = false) Integer status,
            @Parameter(description = "分页参数") PageQuery pageQuery) {
        
        logger.debug("分页查询菜单请求: current={}, size={}", 
            (pageQuery != null ? pageQuery.getCurrent() : null), (pageQuery != null ? pageQuery.getSize() : null));
        
        long current = PageUtils.current(pageQuery);
        long size = PageUtils.size(pageQuery);
        
        // 实现带条件的分页查询
        Page<Menu> menuPage;
        
        if (StringUtils.hasText(menuType) || 
            StringUtils.hasText(menuName) || 
            status != null) {
            
            // 使用带条件的分页查询
            logger.debug("带条件的菜单分页查询: menuType={}, menuName={}, status={}", 
                       menuType, menuName, status);
            menuPage = menuService.getMenuPage(current, size, menuType, menuName, status);
        } else {
            // 简单分页查询
            menuPage = menuService.getMenuPage(current, size);
        }
        
        // 转换为DTO并封装分页响应
        PageResponse<MenuDTO> response = PageConverters.map(
            menuPage.getRecords(),
            menuPage.getTotal(),
            menuPage.getCurrent(),
            menuPage.getSize(),
            MenuDTO::fromEntity
        );
        
        logger.debug("分页查询菜单成功: total={}, current={}, size={}", 
            menuPage.getTotal(), menuPage.getCurrent(), menuPage.getSize());
        
        return Result.success("查询成功", response);
    }
    
    /**
     * 获取所有菜单
     */
    @GetMapping("/all")
    @RequiresPermission("menu:query")
    @Operation(summary = "获取所有菜单", description = "获取当前租户下的所有菜单")
    public Result<List<MenuDTO>> getAllMenus() {
        
        logger.debug("获取所有菜单请求");
        
        String tenantId = AuthContextUtils.getCurrentTenantId();
        List<Menu> menus = menuService.getMenusByTenant(tenantId);
        
        // 转换为DTO
        List<MenuDTO> menuDTOs = PageConverters.mapList(menus, MenuDTO::fromEntity);
        
        logger.debug("获取所有菜单成功: count={}", menus.size());
        
        return Result.success("获取成功", menuDTOs);
    }
    
    /**
     * 根据菜单类型获取菜单列表
     */
    @GetMapping("/type/{menuType}")
    @RequiresPermission("menu:query")
    @Operation(summary = "根据类型获取菜单", description = "根据菜单类型获取菜单列表")
    public Result<List<MenuDTO>> getMenusByType(
            @Parameter(description = "菜单类型") @PathVariable String menuType) {
        
        logger.debug("根据类型获取菜单请求: menuType={}", 
            menuType);
        
        String tenantId = AuthContextUtils.getCurrentTenantId();
        List<Menu> menus = menuService.getMenusByType(menuType, tenantId);
        
        // 转换为DTO
        List<MenuDTO> menuDTOs = menus.stream()
                .map(MenuDTO::fromEntity)
                .collect(java.util.stream.Collectors.toList());
        
        logger.debug("根据类型获取菜单成功: menuType={}, count={}", 
            menuType, menus.size());
        
        return Result.success("获取成功", menuDTOs);
    }
    
    // ==================== 菜单树形结构 ====================
    
    /**
     * 获取菜单树
     */
    @GetMapping("/tree")
    @RequiresPermission("menu:query")
    @Operation(summary = "获取菜单树", description = "获取菜单的树形结构")
    public Result<List<MenuDTO>> getMenuTree() {
        
        logger.debug("获取菜单树请求");
        
        String tenantId = AuthContextUtils.getCurrentTenantId();
        List<Menu> menus = menuService.getMenuTree(tenantId);

        // 递归转换为DTO，包含children
        java.util.function.Function<Menu, MenuDTO> convert = new java.util.function.Function<Menu, MenuDTO>() {
            @Override
            public MenuDTO apply(Menu m) {
                MenuDTO dto = MenuDTO.fromEntity(m);
                if (m != null && m.getChildren() != null && !m.getChildren().isEmpty()) {
                    java.util.List<MenuDTO> childDtos = m.getChildren().stream()
                            .map(this::apply)
                            .collect(Collectors.toList());
                    dto.setChildren(childDtos);
                }
                return dto;
            }
        };

        List<MenuDTO> menuTree = menus.stream()
                .map(convert)
                .collect(Collectors.toList());
        
        logger.debug("获取菜单树成功: count={}", menus.size());
        
        return Result.success("获取成功", menuTree);
    }
    
    
    /**
     * 获取用户可访问的菜单树
     */
    @GetMapping("/tree/user/{userId}")
    @RequiresPermission("menu:query")
    @Operation(summary = "获取用户菜单树", description = "获取指定用户可访问的菜单树")
    public Result<List<MenuDTO>> getUserMenuTree(
            @Parameter(description = "用户ID") @PathVariable String userId) {
        
        logger.debug("获取用户菜单树请求: userId={}", 
            userId);
        
        String tenantId = AuthContextUtils.getCurrentTenantId();
        List<Menu> menus = menuService.getUserVisibleMenus(userId, tenantId);
        
        // 转换为DTO
        List<MenuDTO> menuTree = menus.stream()
                .map(MenuDTO::fromEntity)
                .collect(java.util.stream.Collectors.toList());
        
        logger.debug("获取用户菜单树成功: userId={}, count={}", userId, menus.size());
        
        return Result.success("获取成功", menuTree);
    }
    
    /**
     * 获取子菜单
     */
    @GetMapping("/{menuId}/children")
    @RequiresPermission("menu:query")
    @Operation(summary = "获取子菜单", description = "获取指定菜单的直接子菜单")
    public Result<List<MenuDTO>> getChildMenus(
            @Parameter(description = "父菜单ID") @PathVariable String menuId) {
        
        logger.debug("获取子菜单请求: parentMenuId={}", menuId);
        
        String tenantId = AuthContextUtils.getCurrentTenantId();
        List<Menu> childMenus = menuService.getChildMenus(menuId);
        
        // 转换为DTO
        List<MenuDTO> menuDTOs = PageConverters.mapList(childMenus, MenuDTO::fromEntity);
        
        logger.debug("获取子菜单成功: parentMenuId={}, count={}", menuId, childMenus.size());
        
        return Result.success("获取成功", menuDTOs);
    }
    
    // ==================== 菜单权限管理 ====================
    
    /**
     * 获取菜单关联的权限
     */
    @GetMapping("/{menuId}/permissions")
    @RequiresPermission("menu:query")
    @Operation(summary = "获取菜单权限", description = "获取菜单关联的权限列表")
    public Result<List<String>> getMenuPermissions(
            @Parameter(description = "菜单ID") @PathVariable String menuId) {
        
        logger.debug("获取菜单权限请求: menuId={}", menuId);
        
        String tenantId = AuthContextUtils.getCurrentTenantId();
        List<Permission> permissions = menuService.getMenuPermissions(menuId, tenantId);

        // 转换为权限ID列表（保持与实体一致的 String 类型）
        List<String> permissionIds = permissions.stream()
                .map(Permission::getId)
                .filter(java.util.Objects::nonNull)
                .collect(Collectors.toList());
        
        logger.debug("获取菜单权限成功: menuId={}, permissionCount={}", 
            menuId, permissionIds.size());
        
        return Result.success("获取成功", permissionIds);
    }
    
    
    // ==================== 菜单状态管理 ====================
    
    /**
     * 更新菜单状态
     */
    @PutMapping("/{menuId}/status")
    @RequiresPermission("menu:update")
    @RateLimit(count = 30, time = 1)
    @Operation(summary = "更新菜单状态", description = "启用或禁用指定菜单")
    public Result<Void> updateMenuStatus(
            @Parameter(description = "菜单ID") @PathVariable String menuId,
            @Parameter(description = "状态：1-启用，0-禁用") @RequestParam Integer status) {
        
        logger.info("更新菜单状态请求: menuId={}, status={}", menuId, status);
        
        String tenantId = AuthContextUtils.getCurrentTenantId();
        
        // 验证状态值
        if (status == null || (status != 0 && status != 1)) {
            logger.warn("菜单状态值无效: menuId={}, status={}", menuId, status);
            return Result.error("状态值必须是0或1");
        }
        
        // 更新菜单状态
        boolean success = menuService.updateMenuStatus(menuId, status, tenantId);
        logger.info("菜单状态更新{}：menuId={}, status={}", 
                  success ? "成功" : "失败", menuId, status);
        
        if (!success) {
            logger.warn("更新菜单状态失败: menuId={}", menuId);
            return Result.error("菜单不存在或更新失败");
        }
        
        logger.info("更新菜单状态成功: menuId={}, status={}", menuId, status);
        return Result.<Void>success("菜单状态更新成功", null);
    }
    
    /**
     * 更新菜单可见性
     */
    @PutMapping("/{menuId}/visible")
    @RequiresPermission("menu:update")
    @RateLimit(count = 30, time = 1)
    @Operation(summary = "更新菜单可见性", description = "设置菜单是否可见")
    public Result<Void> updateMenuVisible(
            @Parameter(description = "菜单ID") @PathVariable String menuId,
            @Parameter(description = "是否可见：true-可见，false-隐藏") @RequestParam Boolean visible) {
        
        logger.info("更新菜单可见性请求: menuId={}, visible={}", menuId, visible);
        
        String tenantId = AuthContextUtils.getCurrentTenantId();
        
        // 验证可见性值
        if (visible == null) {
            logger.warn("菜单可见性值无效: menuId={}, visible={}", menuId, visible);
            return Result.error("可见性值不能为空");
        }
        
        // 更新菜单可见性
        boolean success = menuService.updateMenuVisible(menuId, visible, tenantId);
        logger.info("菜单可见性更新{}：menuId={}, visible={}", 
                  success ? "成功" : "失败", menuId, visible);
        
        if (!success) {
            logger.warn("更新菜单可见性失败: menuId={}", menuId);
            return Result.error("菜单不存在或更新失败");
        }
        
        logger.info("更新菜单可见性成功: menuId={}, visible={}", menuId, visible);
        return Result.<Void>success("菜单可见性更新成功", null);
    }
    
    // ==================== 菜单统计 ====================
    
    /**
     * 获取菜单统计信息
     */
    @GetMapping("/statistics")
    @RequiresPermission("menu:query")
    @Operation(summary = "获取菜单统计信息", description = "获取菜单的统计数据")
    public Result<MenuStatistics> getMenuStatistics() {
        
        logger.debug("获取菜单统计信息请求");
        
        String tenantId = AuthContextUtils.getCurrentTenantId();
        
        // 实现菜单统计逻辑
        MenuStatistics statistics = new MenuStatistics();
        List<Menu> allMenus = menuService.getMenusByTenant(tenantId);
        
        if (allMenus != null && !allMenus.isEmpty()) {
            statistics.setTotalMenus(allMenus.size());
            
            // 状态统计
            long enabledCount = allMenus.stream()
                    .filter(m -> m != null && Integer.valueOf(1).equals(m.getStatus()))
                    .count();
            statistics.setEnabledMenus((int) enabledCount);
            statistics.setDisabledMenus(allMenus.size() - (int) enabledCount);
            
            // 类型统计
            java.util.Map<String, Integer> typeStats = allMenus.stream()
                    .filter(m -> m != null && m.getMenuType() != null)
                    .collect(Collectors.groupingBy(
                        Menu::getMenuType,
                        Collectors.collectingAndThen(
                            Collectors.counting(),
                            Math::toIntExact
                        )
                    ));
            // 设置各类型菜单统计
            statistics.setDirectoryMenus(typeStats.getOrDefault("M", 0));
            statistics.setPageMenus(typeStats.getOrDefault("C", 0));
            statistics.setButtonMenus(typeStats.getOrDefault("F", 0));
            
            // 可见性统计
            long visibleCount = allMenus.stream()
                    .filter(m -> m != null && Boolean.TRUE.equals(m.getVisible()))
                    .count();
            statistics.setVisibleMenus((int) visibleCount);
            statistics.setHiddenMenus(allMenus.size() - (int) visibleCount);
            
            logger.debug("菜单统计完成: 总数={}, 启用={}, 禁用={}, 可见={}", 
                       statistics.getTotalMenus(), statistics.getEnabledMenus(),
                       statistics.getDisabledMenus(), statistics.getVisibleMenus());
        } else {
            // 没有菜单数据时的默认统计
            statistics.setTotalMenus(0);
            statistics.setEnabledMenus(0);
            statistics.setDisabledMenus(0);
            statistics.setVisibleMenus(0);
            statistics.setHiddenMenus(0);
            // 设置默认类型统计值
            statistics.setDirectoryMenus(0);
            statistics.setPageMenus(0);
            statistics.setButtonMenus(0);
            
            logger.debug("没有菜单数据，返回空统计");
        }
        
        // 可见性与类型统计已在上方计算完成，这里不再重复计算
        
        // 层级统计
        if (allMenus == null) {
            allMenus = Collections.emptyList();
        }
        long rootCount = allMenus.stream()
                .filter(m -> m.getParentId() == null)
                .count();
        statistics.setRootMenus((int) rootCount);
        statistics.setChildMenus(allMenus.size() - (int) rootCount);
        
        logger.debug("获取菜单统计信息成功: total={}", statistics.getTotalMenus());
        
        return Result.success("获取成功", statistics);
    }
}
